package com.dragee.modules.sys.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dragee.common.PageUtils;
import com.dragee.common.constants.UserConstants;
import com.dragee.constants.AuthConstants;
import com.dragee.constants.CommonConstants;
import com.dragee.modules.sys.dao.SysUserRoleMapper;
import com.dragee.modules.sys.dao.UserDao;
import com.dragee.modules.sys.entity.LoginUser;
import com.dragee.modules.sys.entity.SysRole;
import com.dragee.modules.sys.entity.SysUserRole;
import com.dragee.modules.sys.entity.UserEntity;
import com.dragee.modules.sys.po.RolePo;
import com.dragee.modules.sys.service.ISysRoleService;
import com.dragee.modules.sys.service.UserService;
import com.dragee.modules.sys.vo.UpdatePasswordVo;
import com.dragee.utils.RedisUtil;
import com.dragee.utils.StringUtils;
import com.dragee.utils.WrapperUtil;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Service("userService")
public class UserServiceImpl extends ServiceImpl<UserDao, UserEntity> implements UserService {

    @Resource
    private UserDao userDao;
    @Resource
    private SysUserRoleMapper userRoleMapper;
    @Autowired
    private ISysRoleService rolesService;

    private SysRoleServiceImpl sysRoleService;

    final private String business = "user";

    @Override
    public List<String> getRoleNamesByUserId(String userId) {
        List<String> names = new ArrayList<>();
        List<SysUserRole> urs = userRoleMapper.selectList(new QueryWrapper<SysUserRole>().eq("user_id", userId));
        List<Long> roleIds = urs.stream().map(SysUserRole::getRoleId).collect(Collectors.toList());
        if (roleIds.size() <= 0) {
            return names;
        }
        List<SysRole> sysRoles = rolesService.list(new QueryWrapper<SysRole>().in("role_id",roleIds));
        names = sysRoles.stream().sorted(new Comparator<SysRole>() {
            @Override
            public int compare(SysRole o1, SysRole o2) {
                return o1.getLevel()-o2.getLevel();
            }
        }).map(SysRole::getRoleName).collect(Collectors.toList());

        return names;
    }

    @Override
    public boolean isHasNextUser(String userId) {
        return  this.count(new QueryWrapper<UserEntity>().eq("parentId", userId)) > 0 ? true : false;
    }

    @Override
    public List<RolePo> getRolePoByUserId(String userId) {
        List<SysUserRole> urs = userRoleMapper.selectList(new QueryWrapper<SysUserRole>().eq("user_id", userId));
        List<Long> roleIds = urs.stream().map(SysUserRole::getRoleId).collect(Collectors.toList());
        List<SysRole> sysRoles = rolesService.list(new QueryWrapper<SysRole>().in("role_id",roleIds).orderByAsc("level"));
        List<RolePo> datas = new ArrayList<>();
        for (SysRole role : sysRoles) {
            datas.add(new RolePo(role.getRoleId(), role.getRoleName(), role.getLevel()));
        }
        return datas;
    }

    @Override
    public RolePo getHighRoleUp(String userId) {
        List<RolePo> roles = getRolePoByUserId(userId);
        RolePo rolePoUp = roles.stream().filter(r -> r.getLevel() >= 0)
                .min((Comparator.comparingInt(RolePo::getLevel))).orElse(null);
        return rolePoUp;
    }

    @Override
    public RolePo getHighRoleDwon(String userId) {
        List<RolePo> roles = getRolePoByUserId(userId);
        RolePo rolePoDown = roles.stream().filter(r -> r.getLevel() < 0)
                .max((Comparator.comparingInt(RolePo::getLevel))).orElse(null);
        return rolePoDown;
    }

    @Override
    public boolean checkPhoneUnique(UserEntity user) {

        Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId();
        UserEntity info = userDao.checkPhoneUnique(user.getPhone());
        if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue())
        {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }

    /**
    * 列表
    */
    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        String userId = params.get("userId") + "";
        params.remove("userId");
        Set<String> parentIds = getParentIds(userId);
        int limit = params.get(CommonConstants.LIMIT) == null
                ?CommonConstants.LIMIT_SIZE:Integer.parseInt(params.get(CommonConstants.LIMIT).toString());
        int start = params.get(CommonConstants.START) == null
                ?CommonConstants.START_SIZE:Integer.parseInt(params.get(CommonConstants.START).toString());
        QueryWrapper<UserEntity> wrapper =
                WrapperUtil.getWrapper(business, params,UserEntity.class);
        IPage<UserEntity> page = new Page<>(start, limit);
        if (parentIds.size() > 0) {
            wrapper.in("parentId", parentIds);
        }
        page = baseMapper.selectPage(page, wrapper.select());

//        for (UserEntity r : page.getRecords()) {
//            List<UserEntity> trees = new ArrayList<>();
//            setUserTree(r, trees);
//        }
        return new PageUtils(page);
    }

    private Set<String> getParentIds (String userId) {
        Set<String> parentIds = new HashSet<>();
        setParentId(userId, parentIds);
        return parentIds;
    }

    private String setParentId (String userId, Set<String> parentIds) {
        parentIds.add(userId);
        List<UserEntity> users = list(new QueryWrapper<UserEntity>().eq("parentId", userId));
        for (UserEntity user : users) {
            parentIds.add(setParentId(user.getUserId() + "", parentIds));
        }
        return userId;
    }


    private UserEntity setUserTree (UserEntity pt, List<UserEntity> trees) {
        List<String> roleNames = getRoleNamesByUserId(pt.getUserId() + "");
        String roleNameStr = StrUtil.join(",", roleNames);
        pt.setRoleNames(roleNameStr);
        pt.setChirdrens(trees);
        List<UserEntity> users = list(new QueryWrapper<UserEntity>().eq("parentId", pt.getUserId()));
        for (UserEntity user : users) {
            trees.add(setUserTree(user, new ArrayList<>()));
        }
        return pt;
    }



    @Override
    public LoginUser getLoginUser(String username, String password) {
        LoginUser loginUser = userDao.getLoginUser(username, password);
        return loginUser;
    }

    @Override
    public List<String> getPerms(Long userId) {
        return userDao.getPerms(userId);
    }

    @Override
    public void updatePassword(UpdatePasswordVo vo) {

        String password = new Sha256Hash(vo.getNewPassword(), AuthConstants.SLAT_PWD).toString();

        vo.setNewPassword(password);
        userDao.updatePassword(vo);

        RedisUtil.del();
    }

    @Override
    public List<UserEntity> getUsersByRole(String roleId) {
        List<SysUserRole> datas = userRoleMapper
                .selectList(new QueryWrapper<SysUserRole>()
                        .eq("role_id", roleId));
        List<Long> userIds = datas.stream().map(SysUserRole::getUserId).collect(Collectors.toList());
        if (userIds.size() == 0) {
            return new ArrayList<>();
        }
        return list(new QueryWrapper<UserEntity>().in("userId", userIds));
    }
}
